package br.edu.ufcg.greengrid.workload;

import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.util.LinkedList;
import java.util.List;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import br.edu.ufcg.greengrid.AbstractTest;

import com.mallardsoft.tuple.Triple;

public class DGTAConverterTest extends AbstractTest {

	private DGTAConverter converter;
	
	@Before
	public void setUp() throws Exception {

		this.converter = new DGTAConverter(new BulkDataImpl<Triple<String, Long, Long>>(new MachineAvailabilityComparator()));
	}

	@After
	public void tearDown() throws Exception {

	}

	@Test
	public void testScenarioNoIdlePeriod() {

		String fileName = "machine1.dat";
		this.converter.convert(fileName, "1 2 -1");
		this.converter.convert(fileName, "2 3 -1");
		this.converter.close();

		List<String> actual = this.converter.getLines();
		assertTrue(actual.isEmpty());
	}

	@SuppressWarnings("serial")
	@Test
	public void testScenarioOneIdlePeriod() {

		String fileName = "machine1.dat";
		this.converter.convert(fileName, "1 2 12345");
		this.converter.convert(fileName, "2 3 12345");
		this.converter.convert(fileName, "3 4 12345");
		this.converter.close();

		List<String> expected = new LinkedList<String>() {
			{
				add(tabulate("machine1 1 3"));
			}
		};

		List<String> actual = this.converter.getLines();

		assertIsEqual(expected, actual);
	}

	@SuppressWarnings("serial")
	@Test
	public void testScenarioTwoIdlePeriods() {

		String fileName = "machine1.dat";
		this.converter.convert(fileName, "1 2 12345");
		this.converter.convert(fileName, "2 3 12345");
		this.converter.convert(fileName, "3 4 12345");
		this.converter.convert(fileName, "4 5 -1");
		this.converter.convert(fileName, "5 6 12345");
		this.converter.convert(fileName, "6 7 12345");
		this.converter.close();

		List<String> expected = new LinkedList<String>() {
			{
				add(tabulate("machine1 1 3"));
				add(tabulate("machine1 5 2"));
			}
		};

		List<String> actual = this.converter.getLines();

		assertIsEqual(expected, actual);
	}

	@SuppressWarnings("serial")
	@Test
	public void testScenarioTwoMachines() {

		String fileNameMachine1 = "machine1.dat";
		String fileNameMachine2 = "machine2.dat";
		this.converter.convert(fileNameMachine1, "1 2 12345");
		this.converter.convert(fileNameMachine1, "2 3 12345");
		this.converter.convert(fileNameMachine2, "3 4 12345");
		this.converter.convert(fileNameMachine2, "4 5 12345");
		this.converter.close();

		List<String> expected = new LinkedList<String>() {
			{
				add(tabulate("machine1 1 2"));
				add(tabulate("machine2 3 2"));
			}
		};

		List<String> actual = this.converter.getLines();

		assertIsEqual(expected, actual);

	}

	@SuppressWarnings("serial")
	@Test
	public void testScenarioTwoMachinesAndTwoIdlePeriodsForEachMachine() {

		String fileNameMachine1 = "machine1.dat";
		String fileNameMachine2 = "machine2.dat";
		this.converter.convert(fileNameMachine1, "1 2 12345");
		this.converter.convert(fileNameMachine1, "2 3 12345");
		this.converter.convert(fileNameMachine1, "3 4 -1");
		this.converter.convert(fileNameMachine1, "4 5 -1");
		this.converter.convert(fileNameMachine1, "5 6 12345");
		this.converter.convert(fileNameMachine1, "6 7 12345");

		this.converter.convert(fileNameMachine2, "7 8 12345");
		this.converter.convert(fileNameMachine2, "8 9 12345");
		this.converter.convert(fileNameMachine2, "9 10 -1");
		this.converter.convert(fileNameMachine2, "10 11 -1");
		this.converter.convert(fileNameMachine2, "11 12 12345");
		this.converter.convert(fileNameMachine2, "12 13 12345");
		this.converter.convert(fileNameMachine2, "13 14 12345");
		this.converter.close();

		List<String> expected = new LinkedList<String>() {
			{
				add(tabulate("machine1 1 2"));
				add(tabulate("machine1 5 2"));
				add(tabulate("machine2 7 2"));
				add(tabulate("machine2 11 3"));
			}
		};

		List<String> actual = this.converter.getLines();

		assertIsEqual(expected, actual);
	}

	@Test
	public void testInsertObservationsWithNoIncreasingTimestamp() {

		String fileNameMachine1 = "machine1.dat";
		this.converter.convert(fileNameMachine1, "1 2 12345");
		this.converter.convert(fileNameMachine1, "3 4 -1");

		try {
			this.converter.convert(fileNameMachine1, "2 3 12345");
			fail("Expected error! The insertion of observations with no increasing timestamp shouldn't be allowed.");
		} catch (IllegalArgumentException e) {
		}
		this.converter.close();

	}

	@SuppressWarnings("serial")
	@Test
	public void testInsertMixedObservationsFromDistinctMachines() {

		String fileNameMachine1 = "machine1.dat";
		String fileNameMachine2 = "machine2.dat";

		// Machine1
		this.converter.convert(fileNameMachine1, "1 2 12345");
		this.converter.convert(fileNameMachine1, "2 3 12345");
		this.converter.convert(fileNameMachine1, "3 4 -1");

		// Machine2
		this.converter.convert(fileNameMachine2, "7 8 12345");
		this.converter.convert(fileNameMachine2, "8 9 12345");
		this.converter.convert(fileNameMachine2, "9 10 -1");

		// Machine1
		this.converter.convert(fileNameMachine1, "4 5 -1");
		this.converter.convert(fileNameMachine1, "5 6 12345");
		this.converter.convert(fileNameMachine1, "6 7 12345");

		// Machine2
		this.converter.convert(fileNameMachine2, "10 11 -1");
		this.converter.convert(fileNameMachine2, "11 12 12345");
		this.converter.convert(fileNameMachine2, "12 13 12345");
		this.converter.convert(fileNameMachine2, "13 14 12345");

		// Finalize converter
		this.converter.close();

		List<String> expected = new LinkedList<String>() {
			{
				add(tabulate("machine1 1 2"));
				add(tabulate("machine1 5 2"));
				add(tabulate("machine2 7 2"));
				add(tabulate("machine2 11 3"));
			}
		};

		List<String> actual = this.converter.getLines();

		assertIsEqual(expected, actual);
	}

	@SuppressWarnings("serial")
	@Test
	public void testScenarioWithHolesInObservations() {

		String fileNameMachine1 = "machine1.dat";

		this.converter.convert(fileNameMachine1, "1 2 12345");
		this.converter.convert(fileNameMachine1, "2 3 12345");
		this.converter.convert(fileNameMachine1, "3 4 -1");
		this.converter.convert(fileNameMachine1, "4 5 -1");
		this.converter.convert(fileNameMachine1, "5 6 12345");
		this.converter.convert(fileNameMachine1, "6 7 12345");
		// Hole in the observations
		this.converter.convert(fileNameMachine1, "10 11 -1");
		this.converter.convert(fileNameMachine1, "11 12 -1");
		this.converter.convert(fileNameMachine1, "12 13 12345");
		this.converter.convert(fileNameMachine1, "13 14 12345");
		this.converter.convert(fileNameMachine1, "14 15 12345");
		this.converter.convert(fileNameMachine1, "15 16 -1");
		this.converter.convert(fileNameMachine1, "16 17 -1");

		this.converter.close();

		List<String> expected = new LinkedList<String>() {
			{
				add(tabulate("machine1 1 2"));
				add(tabulate("machine1 5 2"));
				add(tabulate("machine1 9 3"));
			}
		};

		List<String> actual = this.converter.getLines();

		assertIsEqual(expected, actual);
	}

}
